/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "screen.h"
#include "printf.h"
#include "coil.h"
#include "internalflash.h"
#include "RS485.h"
#include "motor.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
// 485所用的串口缓冲区
uint8_t g_Usart2RxData[16];
uint8_t g_Usart3RxData[16];
// 上位机串口通信接收缓冲区
uint8_t g_Uart6RxData[20];
// 屏幕串口通信接收缓冲区
uint8_t g_Uart5RxData[20];
// 传感器通信接收缓冲区
uint8_t g_Uart4RxData[20];
// 接收中断标志位
uint8_t g_uart6flag = 0;
uint8_t g_uart5flag = 0;
uint8_t g_uart4flag = 0;
// 停止标志位
volatile uint8_t stop_flag = 0;
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

// 验证指令是否合法，帧头为5A A5即为合法
uint8_t VerifyCommand(uint8_t *Data)
{
    uint8_t i = 0;

    for (i = 0; i < 19; i++) {
    	if ((Data[i] == PROTOCOL_HEADER1) && (Data[i + 1] == PROTOCOL_HEADER2)) {
    		return HAL_OK; // 指令合法
    	}
    }
    return HAL_ERROR; // 指令不合法
}

// 将预定模式和实验次数参数,实验时间，转膜时间写入flash
void FlashWriteParam(uint8_t mode, uint8_t times, uint16_t time, uint16_t membrane)
{
	uint8_t WriteData[6] = { 0 };
	WriteData[0] = mode;
	WriteData[1] = times;
	WriteData[2] = (time>> 8) & 0xff;
	WriteData[3] = time & 0xff;
	WriteData[4] = (membrane>> 8) & 0xff;
	WriteData[5] = membrane & 0xff;
	WriteFlashData(ADDR_FLASH_SECTOR_10, WriteData, 6);
}

// 从flash读预定模式和预设实验次数参数
void FlashReadParam(void)
{
	uint8_t ReadData[6];
	ReadFlashData(ADDR_FLASH_SECTOR_10, ReadData, 6); // 从flash读2位数据
	screen_set_param_t.test_gauge_mode = ReadData[0]; // 第一位数据是运行模式
	screen_set_param_t.test_times_param = ReadData[1]; // 第二位数据是预设定的实验次数
	screen_set_param_t.test_time = ((uint16_t)ReadData[2] << 8) | ReadData[3]; // 两位实验时间
	screen_set_param_t.transfer_membrane = ((uint16_t)ReadData[4] << 8) | ReadData[5]; // 两位转膜时间
	printf("mode:%d , times:%d , time:%d , membrane:%d\r\n", screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param, screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
}

// 发送M0读取传感器当前值
int GetSensorValue(void)
{
	HAL_UART_Transmit(&huart4, (const uint8_t *)"M0\r\n", sizeof("M0\r\n"), 0xff);
	HAL_Delay(100);
	int value = (g_Uart4RxData[5] - '0') * 100000 + (g_Uart4RxData[6] - '0') * 10000 + (g_Uart4RxData[8] - '0') * 1000 + (g_Uart4RxData[9] - '0') * 100 + (g_Uart4RxData[10] - '0') * 10 + (g_Uart4RxData[11] - '0');
	return value;
}

// 启动时或校正时获取原点值
void GetOriginPoint(void)
{
	// 打开开关，电机下压
	DRV8870_4_Run(1);
	HAL_Delay(screen_set_param_t.test_time * 100);
	// 获取当前值
	int value = GetSensorValue();
	printf("当前显示值%d\r\n", value);
	// 关闭继电器，恢复初始
	DRV8870_4_Run(0);
	HAL_Delay(50);
	// 存储零点值
	screen_set_param_t.origin_point_param = value;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_UART4_Init();
  MX_UART5_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  MX_USART6_UART_Init();
  /* USER CODE BEGIN 2 */

  HAL_Delay(1000);
  // 从flash读参数
  FlashReadParam();
  // 把参数发到屏幕
  ScreenInit();

  __HAL_UART_ENABLE_IT(&huart5, UART_IT_IDLE); // 开启串口5空闲中断
  HAL_UART_Receive_DMA(&huart5, g_Uart5RxData, 20); // 接收DMA使能

  __HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE); // 开启串口6空闲中断
  HAL_UART_Receive_DMA(&huart6, g_Uart6RxData, 20); // 接收DMA使能

  __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE); // 开启串口4空闲中断
  HAL_UART_Receive_DMA(&huart4, g_Uart4RxData, 20); // 接收DMA使能

  HAL_Delay(1000);
  // 获取原点值
  GetOriginPoint();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

	  if(g_uart4flag == 1) {
		  for(int i = 0; i < 20; i++) {
			  printf("%d: %c", i, g_Uart4RxData[i]);
		  }
		  printf("\r\n");
		  // 清空接收缓冲区和接收标志位
		  for(int i = 0; i < 20; i++) {
			  g_Uart4RxData[i] = 0;
		  }
		  g_uart4flag = 0;
	  }

	  // 循环中写参数到屏幕
	  ScreenSend();
	  // uart5接收中断接收到数据，即屏幕有触碰
	  if(g_uart5flag == 1) {
		  if(VerifyCommand(g_Uart5RxData) != 0) {
			  printf("串口屏发送指令不合法\r\n");
		  }
		  // 判断触碰控件
		  switch(g_Uart5RxData[5]) {
		  case 0x01:
			  printf("首页\r\n");
			  break;
		  case 0x03:
			  printf("系统\r\n");
			  break;
		  case 0x10:
			  // 判断当前运行模式
			  printf("运行模式：");
			  if(screen_set_param_t.test_gauge_mode == 0) {
				  printf("自动运行\r\n");
			  } else {
				  printf("手动运行\r\n");
			  }
			  Run();
			  // 发送数据到debug串口,查看测试数据
			  SendDebug();
			  break;
		  case 0x12:
			  printf("停止\r\n");
			  break;
		  case 0x14:
			  printf("清零\r\n");
			  ScreenSendClear();
			  break;
		  case 0x16:
			  printf("打印\r\n");
			  PrintAllGaugeParameters();
			  break;
		  case 0x18:
			  printf("模式切换：\r\n");
			  if(g_Uart5RxData[8] == 0) {
				  screen_set_param_t.test_gauge_mode = 0;
				  printf("切换成自动\r\n");
			  } else if(g_Uart5RxData[8] == 1){
				  printf("切换成手动\r\n");
				  screen_set_param_t.test_gauge_mode = 1;
			  } else {
				  printf("切换模式error\r\n");
			  }
			  FlashWriteParam(screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param,screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
			  PatternTimesSwitching();
			  break;
		  case 0x02:
			  printf("查询\r\n");
			  break;
		  case 0x05:
			  printf("返回\r\n");
			  break;
		  case 0x2a:
			  screen_set_param_t.test_times_param = g_Uart5RxData[8];
			  printf("手动输入测试次数为%d\r\n", screen_set_param_t.test_times_param);
			  FlashWriteParam(screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param,screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
			  PatternTimesSwitching();
			  break;
		  case 0x2b:
			  printf("实验时长选择\r\n");
			  screen_set_param_t.test_time = ((uint16_t)g_Uart5RxData[7] << 8) | g_Uart5RxData[8];
			  printf("手动输入实验时长为%d\r\n", screen_set_param_t.test_time);
			  FlashWriteParam(screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param,screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
			  PatternTimesSwitching();
			  break;
		  case 0x2e:
			  printf("转膜时长选择\r\n");
			  screen_set_param_t.transfer_membrane = ((uint16_t)g_Uart5RxData[7] << 8) | g_Uart5RxData[8];
			  printf("手动输入转膜时长为%d\r\n", screen_set_param_t.transfer_membrane);
			  FlashWriteParam(screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param,screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
			  PatternTimesSwitching();
			  break;
		  default:
			  printf("error\r\n");
			  break;
		  }
		  // 清空接收缓冲区和接收标志位
		  for(int i = 0; i < 20; i++) {
			  g_Uart5RxData[i] = 0;
		  }
		  g_uart5flag = 0;
	  }

	  // uart6中断接收到数据，即上位机软件有数据下发
	  if(g_uart6flag == 1) {
		  if(VerifyCommand(g_Uart6RxData) != 0) {
			  printf("软件发送指令不合法\r\n");
		  }
		  switch(g_Uart6RxData[5]) {
		  case 0x27:
			  printf("连接成功\r\n");
			  SoftSendData(SOFT_MODE_ADDR, screen_set_param_t.test_gauge_mode);
			  SoftSendData(SOFT_TIMES_ADDR, screen_set_param_t.test_times_param);
			  break;
		  case 0x10:
			  printf("运行\r\n");
			  if(screen_set_param_t.test_gauge_mode == 0) {
				  printf("自动运行\r\n");
			  } else {
				  printf("手动运行\r\n");
			  }
			  Run();
			  // 发送数据到debug串口,查看测试数据
			  SendDebug();
			  break;
		  case 0x12:
			  printf("停止\r\n");
			  break;
		  case 0x14:
			  printf("清零\r\n");
			  ScreenSendClear();
			  break;
		  case 0x26:
			  printf("打印\r\n");
			  PrintAllGaugeParameters();
			  break;
		  case 0x1A:
			  printf("手动自动切换\r\n");
			  if(g_Uart6RxData[9] == 1) {
				  screen_set_param_t.test_gauge_mode = 0;
				  printf("自动\r\n");
			  } else if(g_Uart6RxData[9] == 2){
				  printf("手动\r\n");
				  screen_set_param_t.test_gauge_mode = 1;
			  } else {
				  printf("手动自动切换error\r\n");
			  }
			  FlashWriteParam(screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param, screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
			  PatternTimesSwitching();
			  break;
		  case 0x2A:
			  screen_set_param_t.test_times_param = g_Uart6RxData[9];
			  printf("手动输入测试次数为%d\r\n", g_Uart6RxData[9]);
			  FlashWriteParam(screen_set_param_t.test_gauge_mode, screen_set_param_t.test_times_param, screen_set_param_t.test_time, screen_set_param_t.transfer_membrane);
			  PatternTimesSwitching();
			  break;
		  default:
			  printf("error\r\n");
			  break;
		  }
		  // 清空接收缓冲区和接收标志位
		  for(int i = 0; i < 20; i++) {
			  g_Uart6RxData[i] = 0;
		  }
		  g_uart6flag = 0;
	  }
  }

  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
// printf重定向
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(FILE *f)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}
GETCHAR_PROTOTYPE
{
	uint8_t ch = 0;
	HAL_UART_Receive(&huart1,(uint8_t *)&ch, 1, 0xFFFF);
	if (ch == '\r')
	{
		__io_putchar('\r');
		ch = '\n';
	}
	return __io_putchar(ch);
}


// 串口接收完成回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART2) {
		serial_t.Uart_RX_Flag = 1;
		serial_t.rxByte = g_Usart2RxData[0];
		HAL_UART_Receive_IT(&huart2, g_Usart2RxData, 1);
	}

	if (huart->Instance == USART3) {
		serial_t.Uart_RX_Flag = 1;
		serial_t.rxByte = g_Usart3RxData[0];
		HAL_UART_Receive_IT(&huart3, g_Usart3RxData, 1);
	}
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
